<template>
  <div>
    <el-card shadow="hover" style="width: 100%; margin-bottom: 50px;">
      <template #header>
        <div style="display: flex; justify-content: space-between; align-items: center;">
          <span>文件管理</span>
          <el-button size="small" type="primary" @click="refreshFileTree">刷新数据</el-button>
          <el-button size="small" type="primary" @click="searchFolder">查找目录信息</el-button>
          <el-button size="small" type="primary" @click="searchFile">查询文件信息</el-button>
        </div>
      </template>
      <div class="tree-container">
        <el-tree
          :data="dataSource"
          node-key="id"
          draggable
          :allow-drop="allowDrop" 
          :allow-drag="allowDrag"  
          @node-drop="handleNodeDrop"
          default-expand-all
          :expand-on-click-node="false"
          :show-root="false"
          :row-height="40"
          :node-style="{padding:'10px 0'}"
          style="width: 100%;"
          class="custom-tree">

          <template #default="{ data }">
            <div class="tree-node-container">
              <div class="node-left">
                <el-icon :class="data.type === 'folder' ? 'folder-icon' : 'file-icon'">
                  <Folder v-if="data.type === 'folder'" />
                  <Document v-else />
                </el-icon>
                <div class="node-info">
                  <span>{{ data.name }}</span>
                  <template v-if="data.type === 'file'">
                    <div class="file-meta">
                      {{ formatSize(data.size) }} | {{ data.uploadTime }}
                    </div>
                  </template>
                </div>
              </div>

              <div class="node-actions">
                <template v-if="data.type === 'file'">
                  <el-tooltip :content="data.filesLock === 1 ? '文件解锁' : '文件上锁'" placement="top">
    <el-icon 
    
      :style="{color: data.filesLock ? '#ff4d4f' : ''}">
      <Lock v-if="data.filesLock === 0"   @click.stop="handleLockClick(data.id)"/>
      <Unlock v-else  @click.stop="unlockone(data.id,data.filesLockType)"/>
    </el-icon>
    
  </el-tooltip>  
  <el-dialog 
    v-model="showCameraDialog" 
    title="人脸解锁" 
    width="50%" 
    :close-on-click-modal="false"
    @closed="handleDialogClosed"
    :key="dialogKey"
  >
    <div class="camera-dialog-content">
      <CameraComponent 
        v-if="showCameraDialog" 
        ref="cameraComponent"
      />
      
      <div class="dialog-actions">
        <el-button type="primary" @click="unlockWithFace">使用此照片解锁</el-button>
        <el-button @click="showCameraDialog = false">取消</el-button>
      </div>
    </div>
  </el-dialog>
                  
                  <!-- 带锁定状态判断的操作按钮 -->
                  <el-tooltip v-if="data.filesLock === 0" content="重命名" placement="top">
                    <el-icon @click.stop="renameFile(data.id)"><Edit /></el-icon>
                  </el-tooltip>
                  
                  <el-tooltip v-if="data.filesLock === 0" content="删除文件" placement="top">
                    <el-icon @click.stop="deleteFile(data.id)"><Delete /></el-icon>
                  </el-tooltip>
                  
                  <!-- 只保留下载按钮，触发下载事件 -->
                  <el-tooltip content="下载文件" placement="top">
  <el-icon @click.stop="startDownload(data)"><Download /></el-icon>
</el-tooltip>
                </template>
                <template v-if="data.type === 'folder'">
                  <el-tooltip content="新建文件夹" placement="top">
                    <el-icon @click.stop="createFolder(data.path)"><FolderAdd /></el-icon>
                  </el-tooltip>
                  <el-tooltip v-if="data.name !== '根目录'" content="重命名" placement="top">
                    <el-icon @click.stop="renameFolder(data.id,data.path)"><Edit /></el-icon>
                  </el-tooltip>
                  <el-tooltip v-if="data.name !== '根目录'" content="删除目录" placement="top">
                    <el-icon @click.stop="deleteFolder(data.id)"><Delete /></el-icon>
                  </el-tooltip>
                  <el-tooltip content="上传文件" placement="top">
                    <el-icon @click.stop="openUploadDialog(data.id)"><Upload /></el-icon>
                  </el-tooltip>
                </template>
              </div>
            </div>
          </template>
        </el-tree>
      </div>
    </el-card>

    <file-upload-dialog
      v-model="uploadDialogVisible"
      :folder-id="currentFolderId"
      @upload-success="refreshFileTree"
    />
  </div>
</template>

<script lang="ts" setup>
import { ElMessageBox, ElMessage } from 'element-plus';
import { ref, onMounted, defineEmits } from 'vue';
import FileUploadDialog from './UploadDialog.vue';
import { ElTree } from 'element-plus';
import axios from 'axios';
import {
  Document,
  Folder,
  Delete,
  Edit,
  Download,
  Upload,
  Lock,
  Unlock,
  FolderAdd
} from '@element-plus/icons-vue'
import eventBus from '@/utils/eventBus';
import { useDownloadStore } from '@/stores/downloadStore';
import { User } from '@element-plus/icons-vue';
const downloadStore = useDownloadStore();
const uploadDialogVisible = ref(false);
const allowDrag = (node: ElTreeNode) => {
  // 仅允许文件类型拖拽
  return node.data.type === 'file';
};

const allowDrop = (draggingNode: ElTreeNode, dropNode: ElTreeNode): boolean => {
  // 禁止文件夹之间的拖拽
  if (dropNode.data.type === 'file') {
    return false;
  }
  // 最终校验结果
  return true;
};

const handleNodeDrop = async (draggingNode: ElTreeNode, dropNode: ElTreeNode) => {
  try {
    const { data } = await axios.put('http://localhost:8083/files/move', null, {
      params: {
        filesId: draggingNode.data.id,
        targetFolderId: dropNode.data.id
      }
    });

    if (data.success) {
      ElMessage.success({
        message: '移动成功',
        grouping: true,
        duration: 2000
      });
      refreshFileTree();
    } else {
      refreshFileTree();
      ElMessage.error({
        message: `移动失败：${data.data || '无法移动'}`,
        grouping: true
      });
    }
  } catch (error) {
    ElMessage.error({
      message: '操作失败：' + (error.response?.data?.message || '无法移动'),
      grouping: true
    });
    refreshFileTree();
  }
};

// 处理上传按钮点击
const currentFolderId = ref<number>(0);

const openUploadDialog = (folderId: number) => {
  currentFolderId.value = folderId;
  uploadDialogVisible.value = true;
};

interface Tree {
  id: number;
  name: string;
  type: 'folder' | 'file';
  path: string;
  children?: Tree[];
  size?: number;
  uploadTime?: string;
  filesLock?:number;
  fileType?: string; 
  filesLockType?:string;
}
const dataSource = ref<Tree[]>([]);
// 格式化文件大小
const formatSize = (bytes: number | undefined): string => {
  if (!bytes) return '0 B';
  if (bytes < 1024) return bytes + ' B';
  if (bytes < 1048576) return (bytes / 1024).toFixed(1) + ' KB';
  return (bytes / 1048576).toFixed(1) + ' MB';
};
const refreshFileTree = () => {
  axios.get('http://localhost:8083/filesystem/tree')
   .then(response => {
      if (response.data.success) {
        dataSource.value = [response.data.data];
      }
    })
   .catch(error => {
      console.error('获取文件系统数据失败:', error);
    });
}

onMounted(() => {
  refreshFileTree();
});

// 定义emits
const emit = defineEmits(['download-file']);

// 触发下载事件
// 修改下载按钮点击处理
 const startDownload = (file: Tree) => {
   // 检查文件是否已锁定
   if (file.filesLock === 1) {
     ElMessage.warning('文件已锁定，无法下载');
     return;
   }
   
   // 添加到下载队列
   downloadStore.addDownload({
     id: file.id,
     name: file.name,
     fileType: file.fileType,
     size: file.size
   });
   
   ElMessage.success('已添加到下载队列');
 }

const searchFile = async () => {
  try {
    const { value } = await ElMessageBox.prompt(
      '请输入搜索关键词',
      '文件搜索',
      {
        confirmButtonText: '搜索',
        cancelButtonText: '取消',
        inputPattern: /^[^$%\/|\\!]*$/, 
        inputErrorMessage: '关键词不能包含特殊字符 $%/|\\!'
      }
    );

    if (value) {
      const response = await axios.get('http://localhost:8083/files/search', {
        params: {
          keyword: encodeURIComponent(value.trim())
        }
      });
        dataSource.value = response.data;
    }
  } catch (error) {
    if (error !== 'cancel') {
      console.error('文件搜索失败:', error);
      ElMessage.error(`搜索失败: ${error.response?.data?.message || error.message}`);
    }
  }
};

// 修改lock方法为handleLockClick，并添加选择逻辑
const handleLockClick = async (filesId: number) => {
  try {
    // 使用自定义对话框选择上锁方式
    const lockMethod = await showLockMethodDialog();
    
    if (!lockMethod) return; // 用户取消选择
    
    // 根据用户选择调用不同方法
    if (lockMethod === 'password') {
      await lockWithPassword(filesId);
    } else if (lockMethod === 'biometric') {
      await lockWithBiometric(filesId);
    }
  } catch (error) {
    // 用户取消操作不做处理
    console.error('上锁操作取消:', error);
  }
};

// 显示上锁方式选择对话框（自定义实现）
const showLockMethodDialog = (): Promise<'password' | 'biometric' | null> => {
  return new Promise((resolve) => {
    // 创建对话框容器
    const dialog = document.createElement('div');
    dialog.className = 'lock-method-dialog';
    dialog.style.cssText = `
      position: fixed;
      top: 50%;
      left: 50%;
      transform: translate(-50%, -50%);
      background: white;
      padding: 20px;
      border-radius: 8px;
      box-shadow: 0 2px 12px 0 rgba(0,0,0,0.1);
      z-index: 2000;
      min-width: 300px;
    `;
    
    // 对话框标题
    const title = document.createElement('h3');
    title.textContent = '选择上锁方式';
    title.style.marginTop = '0';
    dialog.appendChild(title);
    
    // 创建选项容器
    const optionsContainer = document.createElement('div');
    optionsContainer.style.margin = '15px 0';
    
    // 密码选项
    const passwordOption = createOption('password', '密码上锁', '🔒');
    // 生物特征选项
    const biometricOption = createOption('biometric', '生物特征上锁', '👤');
    
    optionsContainer.appendChild(passwordOption);
    optionsContainer.appendChild(biometricOption);
    dialog.appendChild(optionsContainer);
    
    // 创建按钮容器
    const buttonContainer = document.createElement('div');
    buttonContainer.style.display = 'flex';
    buttonContainer.style.justifyContent = 'flex-end';
    buttonContainer.style.gap = '10px';
    
    // 取消按钮
    const cancelButton = document.createElement('button');
    cancelButton.textContent = '取消';
    cancelButton.onclick = () => {
      document.body.removeChild(dialog);
      document.body.removeChild(overlay);
      resolve(null);
    };
    
    // 确定按钮
    const confirmButton = document.createElement('button');
    confirmButton.textContent = '确定';
    confirmButton.style.backgroundColor = '#409eff';
    confirmButton.style.color = 'white';
    confirmButton.onclick = () => {
      const selected = document.querySelector('input[name="lockMethod"]:checked');
      if (!selected) {
        alert('请选择上锁方式');
        return;
      }
      document.body.removeChild(dialog);
      document.body.removeChild(overlay);
      resolve(selected.id as 'password' | 'biometric');
    };
    
    buttonContainer.appendChild(cancelButton);
    buttonContainer.appendChild(confirmButton);
    dialog.appendChild(buttonContainer);
    
    // 创建遮罩层
    const overlay = document.createElement('div');
    overlay.style.cssText = `
      position: fixed;
      top: 0;
      left: 0;
      right: 0;
      bottom: 0;
      background: rgba(0,0,0,0.5);
      z-index: 1999;
    `;
    
    // 添加到DOM
    document.body.appendChild(overlay);
    document.body.appendChild(dialog);
  });
};

// 创建选项元素
const createOption = (id: string, text: string, icon: string) => {
  const container = document.createElement('div');
  container.style.display = 'flex';
  container.style.alignItems = 'center';
  container.style.marginBottom = '10px';
  container.style.padding = '8px';
  container.style.borderRadius = '4px';
  container.style.cursor = 'pointer';
  container.onmouseover = () => container.style.backgroundColor = '#f5f7fa';
  container.onmouseout = () => container.style.backgroundColor = 'transparent';
  
  // 单选框
  const radio = document.createElement('input');
  radio.type = 'radio';
  radio.name = 'lockMethod';
  radio.id = id;
  radio.value = id;
  radio.style.marginRight = '10px';
  
  // 默认选中密码选项
  if (id === 'password') radio.checked = true;
  
  // 图标
  const iconElement = document.createElement('span');
  iconElement.textContent = icon;
  iconElement.style.marginRight = '8px';
  iconElement.style.fontSize = '20px';
  
  // 文本
  const label = document.createElement('label');
  label.htmlFor = id;
  label.textContent = text;
  label.style.cursor = 'pointer';
  
  container.appendChild(radio);
  container.appendChild(iconElement);
  container.appendChild(label);
  
  // 点击整个容器选择选项
  container.onclick = () => radio.checked = true;
  
  return container;
};

// 密码上锁方法
const lockWithPassword = async (filesId: number) => {
  try {
    const { value: password } = await ElMessageBox.prompt('请输入密码', '文件上锁', {
      confirmButtonText: '确定',
      cancelButtonText: '取消',
      inputType: 'password'
    });
    
    if (!password) return;
    
    const response = await axios.post(
      `http://localhost:8083/files/lock?filesId=${filesId}&password=${encodeURIComponent(password)}`,
      null
    );
    
    if (response.data.success) {
      ElMessage.success('上锁成功');
      refreshFileTree();
    } else {
      ElMessage.error(response.data.errorMsg || '上锁失败');
    }
  } catch (error) {
    if (error.response) {
      ElMessage.error(error.response.data.errorMsg || '上锁失败');
    } else {
      ElMessage.error(error.message || '请求失败');
    }
  }
};

// 生物特征上锁方法（使用按钮单选框选择方式）
const lockWithBiometric = async (filesId: number) => {
  try {
    // 发送请求
    const response = await axios.post(
      `http://localhost:8083/files/lockone?filesId=${filesId}`,
    );
    
    if (response.data.success) {
      ElMessage.success('生物特征上锁成功');
      refreshFileTree();
    } else {
      ElMessage.error('请去申请人脸密钥');
      ElMessage.error(response.data.errorMsg || '生物特征上锁失败');
      ElMessage.error('请去申请人脸密钥');
    }
  } catch (error) {
    if (error.response) {
      ElMessage.error('请去申请人脸密钥');
      ElMessage.error(error.response.data.errorMsg || '生物特征上锁失败');
    } else {
      ElMessage.error(error.message || '请求失败');
    }
  }
};


  





import CameraComponent from './CameraComponent.vue';

// 文件数据接口
interface FileData {
  id: number;
  filesLock: number;
  filesLockType: string;
}

// 属性
const props = defineProps({
  data: {
    type: Object as () => FileData,
    required: true
  }
});

// 拍照组件引用
const cameraComponent = ref<InstanceType<typeof CameraComponent> | null>(null);
const showCameraDialog = ref(false);
const currentUnlockFileId = ref<number | null>(null);
  const dialogKey = ref(0); // 用于强制重新创建对话框

// 对话框关闭时重置状态
const handleDialogClosed = () => {
  currentUnlockFileId.value = null;
  dialogKey.value += 1; // 修改key强制销毁并重新创建组件
};
// 解锁方法 - 根据上锁类型选择解锁方式
const unlockone = async (fileId: number, lockType: string) => {
  try {
    if (lockType === 'Password') {
      await unlock(fileId);
    } else if (lockType === 'Face') {
      // 先关闭可能存在的对话框
      showCameraDialog.value = false;
      
 
      
      currentUnlockFileId.value = fileId;
      dialogKey.value += 1; // 修改key强制销毁并重新创建组件
      showCameraDialog.value = true;
    } else {
      ElMessage.warning(`未知的上锁类型: ${lockType}`);
    }
  } catch (error) {
    console.error('解锁失败:', error);
    ElMessage.error('解锁失败，请重试');
  }
};
// 密码解锁方法
const unlock = async (fileId: number) => {
  try {
    const { value: password } = await ElMessageBox.prompt('请输入密码', '文件解锁', {
      confirmButtonText: '确定',
      cancelButtonText: '取消',
      inputType: 'password'
    });
    
    if (!password) return;
    
    const response = await axios.post(
      `http://localhost:8083/files/unlock?filesId=${fileId}&password=${encodeURIComponent(password)}`,
      null
    );
    
    if (response.data.success) {
      ElMessage.success('解锁成功');
      refreshFileTree();
    } else {
      ElMessage.error(response.data.errorMsg || '解锁失败');
      if (response.data.errorMsg === "抱歉，该用户暂时锁定") {
        localStorage.removeItem('token'); 
        setTimeout(() => {
          window.location.href = '/login'; 
        }, 1500);
      }
    }
  } catch (error) {
    if (error.response) {
      ElMessage.error(error.response.data.errorMsg || '解锁失败');
    } else {
      ElMessage.error(error.message || '请求失败');
    }
  }
};

// 人脸解锁方法
const unlockWithFace = async () => {
  if (!cameraComponent.value || currentUnlockFileId.value === null) return;
  
  try {
    // 获取照片的Blob对象
    const photoBlob = cameraComponent.value.getPhotoBlob();
    if (!photoBlob) {
      ElMessage.warning('请先拍照');
      return;
    }
    
    // 创建表单数据
    const formData = new FormData();
    formData.append('file', photoBlob, 'face.jpg');
    formData.append('filesId', currentUnlockFileId.value.toString());
    
    // 发送解锁请求
    const response = await axios.post('http://localhost:8083/files/unlockWithFace', formData, {
      headers: {
        'Content-Type': 'multipart/form-data'
      }
    });
    
    if (response.data.success) {
      ElMessage.success('人脸解锁成功');
      refreshFileTree();
      showCameraDialog.value = false;
    } else {
      ElMessage.error(response.data.errorMsg || '人脸解锁失败');
    }
  } catch (error) {
    console.error('人脸解锁请求失败:', error);
    ElMessage.error('人脸解锁失败: ' + error.message);
  }
};


//创建文件夹
const createFolder = async (path: string) => { 
   const { value } = await ElMessageBox.prompt("请输入新文件夹名","新建文件夹",{ 
       inputValidator: (value) => {
         // 验证输入不为空
         if (!value) { 
           return '请输入创建文件夹的名称'; 
         }
         // 验证不包含特殊字符和违规字符串
         const forbiddenChars = /[\$%\/|\\!]/;
         const forbiddenWords = ['exe','dll','php','.'];
         if (forbiddenChars.test(value)) {
           return '文件夹名不能包含特殊字符 $%/|\\!';
         }
         if (forbiddenWords.some(word => value.toLowerCase().includes(word))) {
           return '文件夹名不能包含违规字符串';
         }
         return true; 
       } 
     }); 
     const newFolder = path + '/' + value;
     try {
    const formData = new FormData();
    formData.append('path', newFolder);
    
    const response = await axios.post('http://localhost:8083/folders/createFolder', formData, {
      headers: {
        'Content-Type': 'multipart/form-data'
      }
    });
       if (response.data.success) { 
         ElMessage.success('创建成功');
         refreshFileTree();
       } else{ 
         ElMessage.error('创建失败'+response.data.errorMsg);
       }
     } catch (error) { 
       ElMessage.error('创建失败');
     } 
};

//重命名文件夹
const renameFolder = async (folderId: string, currentPath: string) => {
  const { value } = await ElMessageBox.prompt("请输入新文件夹名", "重命名文件夹", {
    inputValidator: (value) => {
      // 验证输入不为空
      if (!value) {
        return '请输入新文件夹名称';
      }
      // 验证不包含特殊字符和违规字符串
      const forbiddenChars = /[\$%\/|\\!]/;
      const forbiddenWords = ['exe','dll','php'];
      if (forbiddenChars.test(value)) {
        return '文件夹名不能包含特殊字符 $%/|\\!';
      }
      if (forbiddenWords.some(word => value.toLowerCase().includes(word))) {
        return '文件夹名不能包含违规字符串';
      }
      return true;
    }
  });

  const newPath = currentPath.substring(0, currentPath.lastIndexOf('/') + 1) + value;
  
  try {
    const formData = new FormData();
    formData.append('folderId', folderId);
    formData.append('newPath', newPath);
    
    const response = await axios.put('http://localhost:8083/folders/updateFolderPath', formData, {
      headers: {
        'Content-Type': 'multipart/form-data'
      }
    });
    
    if (response.data.success) {
      ElMessage.success('重命名成功');
      refreshFileTree();
    } else {
      ElMessage.error('重命名失败: ' + response.data.errorMsg);
    }
  } catch (error) {
    ElMessage.error('重命名失败');
  }
};

const searchFolder = () => {
  ElMessageBox.prompt('请输入要查询的目录路径', '搜索目录', {
    confirmButtonText: '确定',
    cancelButtonText: '取消',
    inputPattern: /^[^$%/|\\!]*$/,
    inputErrorMessage: '路径不能包含特殊字符 $%/|\\!'
  }).then(({ value }) => {
    if (!value) return;
    
    ElMessageBox.confirm('是否包含文件？', '搜索选项', {
      confirmButtonText: '包含文件',
      cancelButtonText: '仅目录',
      type: 'info'
    }).then(() => {
      // 包含文件
      axios.get(`http://localhost:8083/folders/getFolder?path=${encodeURIComponent(value)}&includeFiles=true`)
        .then(response => {
          if (response.data.success) {
            dataSource.value = response.data.data;
            ElMessage.success('查询成功');
          } else {
            ElMessage.error(response.data.errorMsg || '查询失败');
          }
        })
        .catch(error => {
          ElMessage.error(error.message || '请求失败');
        });
    }).catch(() => {
      // 仅目录
      axios.get(`http://localhost:8083/folders/getFolder?path=${encodeURIComponent(value)}&includeFiles=false`)
        .then(response => {
          if (response.data.success) {
            dataSource.value = response.data.data;
            ElMessage.success('查询成功');
          } else {
            ElMessage.error(response.data.errorMsg || '查询失败');
          }
        })
        .catch(error => {
          ElMessage.error(error.message || '请求失败');
        });
    });
  }).catch(() => {
    // 用户取消
  });
};

const deleteFile = async (fileId: number) => {
  try {
    const response = await axios.delete(`http://localhost:8083/files/${fileId}`);
    
    if (response.data.success) {
    
      ElMessage.success('文件删除成功');
      refreshFileTree();
    } else {
      ElMessage.error('删除失败: ' + response.data.errorMsg);
    }
  } catch (error) {
    console.error('删除文件失败:', error);
    ElMessage.error('删除请求发送失败');
  }
};

// 修改文件名
const renameFile = async (fileId: number) => {
  try {
    // 使用Element UI的输入框获取新文件名
    const { value: newName } = await ElMessageBox.prompt('请输入新文件名', '重命名文件', {
      confirmButtonText: '确定',
      cancelButtonText: '取消',
      inputPattern: /^[^$%/|\\!]*$/, // 过滤特殊字符
      inputErrorMessage: '文件名不能包含特殊字符 $%/|\\!'
    });
    
    if (!newName) return;
    
    // 发送PUT请求，参数直接挂载到URL
    const response = await axios.put(
      `http://localhost:8083/files/rename?filesId=${fileId}&newName=${encodeURIComponent(newName)}`,
      null
    );
    
    if (response.data.success) {
      ElMessage.success('重命名成功');
      refreshFileTree();
    } else {
      ElMessage.error(response.data.errorMsg || '重命名失败');
    }
  } catch (error) {
    if (error.response) {
      ElMessage.error(error.response.data.errorMsg || '重命名失败');
    } else {
      ElMessage.error(error.message || '请求失败');
    }
  }
};

// 删除文件夹
const deleteFolder = async (folderId: number) => { 
   try { 
     const formData = new FormData();
     formData.append('folderId', folderId.toString());
     
     const response = await axios.delete('http://localhost:8083/folders/deleteFolder', {
  data: formData,
  headers: {
    'Content-Type': 'multipart/form-data'
  }
});
     if (response.data.success) {
       refreshFileTree();
       ElMessage.success('删除成功');
     } else {
       ElMessage.error('删除失败: ' + response.data.errorMsg);
     }
   } catch (error) {
     console.error('删除文件夹失败:', error);
     ElMessage.error('删除失败');
   } 
};
</script>

<style>

/* 添加生物特征对话框样式 */
.biometric-method-dialog button {
  padding: 8px 15px;
  border: 1px solid #dcdfe6;
  border-radius: 4px;
  background: white;
  cursor: pointer;
}

.biometric-method-dialog .biometric-option:hover {
  border-color: #c6e2ff;
  background-color: #ecf5ff;
}

/* 上锁方式对话框样式 */
.lock-method-dialog .el-message-box__message {
  padding: 15px 0;
}
.tree-node-container {
  display: flex;
  justify-content: space-between;
  width: 100%;
  padding: 4px 0;
  transition: background-color 0.3s;
  
  &:hover {
    background: #f5f7fa;
  }
}
.node-info {
    display: flex;
    flex-direction: row; 
    align-items: center; 
    line-height: 1.5;
    gap: 8px;  
    
    span {
        white-space: nowrap;
        overflow: hidden;
        text-overflow: ellipsis;
        display: inline-block;  
    }
    
    .file-meta {
        line-height: 1.2;
        margin-top: 0;  
        display: inline-flex; 
        align-items: center;
        gap: 6px;
    }
}
  :deep(.el-tree-node__content):hover {
    background: #f5f7fa;
    .tree-node-container {
      background: transparent;
    }
  }
  :deep(.el-tree-node__content) .el-icon {
    font-size: 18px;
    margin-right: 8px;
  }

.node-left {
  display: flex;
  align-items: center;
  gap: 8px;
}

.node-actions {
  display: flex;
  gap: 12px;
  padding-right: 16px;
  align-items: center;
  
  .el-icon {
    color: #606266;
    cursor: pointer;
    transition: all 0.3s;
    
    &:hover {
      color: #409eff;
      transform: scale(1.1);
    }
    
    &:active {
      transform: scale(0.95);
    }
  }
}
.lock-method-dialog .el-message-box__message {
  padding: 15px 0;
}
.tree-container {
  max-height: 70vh;
  overflow-y: auto;
}
.folder-icon {
  color: #e6a23c;
}
.file-icon {
  color: #909399;
}

.file-meta {
  color: #909399;
  font-size: 12px;
}
.el-tree-node__content.allow-drop {
  box-shadow: 0 0 8px rgba(103,194,58,0.6);
}
.el-tree-node__content.deny-drop {
  box-shadow: 0 0 8px rgba(245,108,108,0.6);
}


.dialog-actions {
  display: flex;
  justify-content: center;
  gap: 15px;
  margin-top: 15px;
}
</style>